using System;
using System.Reflection;

namespace Microsoft.Sdc.Tasks.Configuration.InstalledProducts
{
	/// <summary>
	/// Enforces version comparison for versions strings separated by "." or ","
	/// </summary>
	internal class VersionComparisonChecker : IBinaryComparisonChecker
	{
		private BinaryComparisonOperator _comparisonOperator;
		public BinaryComparisonOperator Operator
		{
			get
			{
				return _comparisonOperator;
			}
			set
			{
				this._comparisonOperator = value;
			}
		}

		public bool IsMatch(object baseObject, object compareObject)
		{
			// assume both strings
			string compareString = (string)compareObject;
			string baseString = (string)baseObject;

			bool result;
			switch (Operator)
			{
				case BinaryComparisonOperator.Equals: 
					result = (CompareVersions(baseString,compareString)==0);
					break;
				case BinaryComparisonOperator.Contains: 
					result = (compareString.IndexOf(baseString)>=0);
					break;
				case BinaryComparisonOperator.GreaterThan:
					result = (CompareVersions(baseString,compareString)>0);
					break;
				case BinaryComparisonOperator.LessThan:
					result = (CompareVersions(baseString,compareString)<0);
					break;
				case BinaryComparisonOperator.GreaterThanOrEquals:
					result = (CompareVersions(baseString,compareString)>=0);
					break;
				case BinaryComparisonOperator.LessThanOrEquals:
					result = (CompareVersions(baseString,compareString)<=0);
					break;
				default: throw new ApplicationException("Binary Operator not supported in this checker:"+Operator);
			}
			return result;
		}

		private int CompareVersions(string baseVersion, string compareVersion)
		{
			return CompareVersions(baseVersion, compareVersion, int.MaxValue);
		}

		private int CompareVersions(string baseVersion, string compareVersion, int limit)
		{
			char segmentDivider;
			if (baseVersion.IndexOf(".")>=0)
			{
				segmentDivider = '.';
			}
			else
			{
				segmentDivider = ',';
			}
			string [] baseVersionSegments = baseVersion.Split(segmentDivider);
			string [] compareVersionSegments = compareVersion.Split(segmentDivider);
			for (int i=0; (i<baseVersionSegments.Length && i<compareVersionSegments.Length && i<limit); i++)
			{
				// Check for wildcards
				if (! (baseVersionSegments[i]=="*" || compareVersionSegments[i]=="*"))
				{
					int baseVersionInt = int.Parse(baseVersionSegments[i],System.Globalization.CultureInfo.InvariantCulture);
					int compareVersionInt = int.Parse(compareVersionSegments[i],System.Globalization.CultureInfo.InvariantCulture);
					if (compareVersionInt<baseVersionInt)
					{
						return 1; // baseVersion is newer
					}
					else if (compareVersionInt>baseVersionInt)
					{
						return -1; // baseVersion is older
					}
					// otherwise equal so look at next segment
				}
			}
			return 0; // equal
		}

		public VersionComparisonChecker(BinaryComparisonOperator op)
		{
			this.Operator = op;
		}
	}
}
